﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Display;
using System.Collections;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.ADF.Connection.Local;
using PlanningGIS.ArcGIS;
using PlanningGIS.Util.Log;

namespace PlanningGIS.Symbol
{
    /// <summary>
    /// 渐变色
    /// </summary>
    public partial class ClassValueRender : UserControl
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public ClassValueRender()
        {
            InitializeComponent();
            List<string> Methods = new List<string>() { "Natural Breaks (Jenks)", "Equal Interval", "Defined Interval", "Quantile", "Standard Deviation", "Geometrical Interval", "Manual" };
            foreach (string method in Methods)
            {
                cmbMethods.Items.Add(method);
            }
            cmbMethods.SelectedIndex = 0;

            for (int i = 1; i < 20; i++)
            {
                cmbClasses.Items.Add(i);
            }
            cmbClasses.SelectedIndex = 4;

            this.editBox.Size = new Size(0, 0);
            this.editBox.Location = new System.Drawing.Point(0, 0);
            this.editBox.BorderStyle = BorderStyle.FixedSingle;
            this.editBox.Font = this.listView.Font;
            this.listView.Controls.Add(this.editBox);
            this.editBox.AutoSize = false;
            this.editBox.KeyPress += new KeyPressEventHandler(this.editBox_KeyPress);
            this.editBox.LostFocus += new EventHandler(this.editBox_LostFocus);

        }

        /// <summary>
        /// 值编辑控件
        /// </summary>
        private TextBox editBox = new TextBox();

        /// <summary>
        /// 是否取消
        /// </summary>
        private bool _IsCancel = false;
        
        /// <summary>
        /// 
        /// </summary>
        ArrayList SymbolList = new ArrayList();

        /// <summary>
        /// 
        /// </summary>
        List<double> BreakList = new List<double>();

        /// <summary>
        /// 
        /// </summary>
        List<double> lowerBreak = new List<double>();

        /// <summary>
        /// 
        /// </summary>
        List<string> labels = new List<string>();

        /// <summary>
        /// 当前操作的单元格
        /// </summary>
        ListViewHitTestInfo _ItemHitTestInfo;
        
        /// <summary>
        /// 
        /// </summary>
        private bool IsReady = false;

        /// <summary>
        /// 要渲染的图层
        /// </summary>
        private IFeatureLayer _FeatureLayer = null;

        /// <summary>
        /// 获取或设置要渲染的图层
        /// </summary>
        public IFeatureLayer FeatureLayer
        {
            set
            {
                _FeatureLayer = value;
                try
                {
                    cmbColorRamp.Init();
                    cmbFields.Items.Clear();
                    cmbFields.Items.Add("<空>");
                    if (_FeatureLayer != null && _FeatureLayer.FeatureClass != null)
                    {
                        for (int i = 0; i < _FeatureLayer.FeatureClass.Fields.FieldCount; i++)
                        {
                            IField fd = _FeatureLayer.FeatureClass.Fields.get_Field(i);
                            switch (fd.Type)
                            {
                                case esriFieldType.esriFieldTypeDouble:
                                case esriFieldType.esriFieldTypeInteger:
                                case esriFieldType.esriFieldTypeSmallInteger:
                                    cmbFields.Items.Add(fd.Name);
                                    break;
                            }
                        }
                    }
                    cmbFields.SelectedIndex = 0;
                    Init();
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorText(ex);
                }

            }
            get
            {
                return _FeatureLayer;
            }
        }

        /// <summary>
        /// 图层的渲染样式
        /// </summary>
        private IClassBreaksRenderer _ClassBreaksRenderer;

        /// <summary>
        /// 获取渲染后的符号
        /// </summary>
        public IClassBreaksRenderer ClassBreaksRenderer
        {
            get
            {
                if (listView.Items.Count < 1) return null;
                IClassBreaksRenderer m_ClassBreaksRenderer = new ClassBreaksRendererClass();
                m_ClassBreaksRenderer.Field = cmbFields.Text;
                m_ClassBreaksRenderer.BreakCount = listView.Items.Count;
                m_ClassBreaksRenderer.MinimumBreak = lowerBreak[0];
                for (int i = 0; i < listView.Items.Count; i++)
                {
                    ListViewItem item = listView.Items[i];
                    m_ClassBreaksRenderer.set_Break(i, BreakList[i]);
                    m_ClassBreaksRenderer.set_Label(i, item.SubItems[2].Text);
                    m_ClassBreaksRenderer.set_Symbol(i, (ISymbol)SymbolList[i]);
                }
                IClassBreaksUIProperties clbUIPro = m_ClassBreaksRenderer as IClassBreaksUIProperties;
                ESRI.ArcGIS.esriSystem.UID uid = new ESRI.ArcGIS.esriSystem.UIDClass();
                switch (cmbMethods.Text)
                {
                    case "Natural Breaks (Jenks)":
                        uid.Value = "{62144BEA-E05E-11D1-AAAE-00C04FA334B3}";
                        break;
                    case "Equal Interval":
                        uid.Value = "{62144BE1-E05E-11D1-AAAE-00C04FA334B3}";
                        break;
                    case "Defined Interval":
                        uid.Value = "{62144BE8-E05E-11D1-AAAE-00C04FA334B3}";
                        break;
                    case "Quantile":
                        uid.Value = "{62144BE9-E05E-11D1-AAAE-00C04FA334B3}";
                        break;
                    case "Standard Deviation":
                        uid.Value = "{DC6D8015-49C2-11D2-AAFF-00C04FA334B3}";
                        break;
                    case "Geometrical Interval":
                        uid.Value = "{C79EB120-E98E-4AF9-903D-70273E0C140E}";
                        break;
                    default:
                        uid = null;
                        break;
                }
                if (uid != null) clbUIPro.Method = uid;
                for (int i = 0; i < lowerBreak.Count; i++)
                {
                    clbUIPro.set_LowBreak(i, lowerBreak[i]);
                }
                IDataSampling pDataSample = m_ClassBreaksRenderer as IDataSampling;
                int maxSampleSize = 20000;
                if (int.TryParse(this.textBox1.Text, out maxSampleSize))
                {
                    pDataSample.MaxSampleSize = maxSampleSize;
                }
                return m_ClassBreaksRenderer;
            }
        }

        /// <summary>
        /// 创建控件
        /// </summary>
        private void Init()
        {
            if (FeatureLayer == null || !(FeatureLayer is IGeoFeatureLayer)) return;
            IFeatureRenderer renderer = (FeatureLayer as IGeoFeatureLayer).Renderer;
            if (renderer == null || !(renderer is IClassBreaksRenderer)) return;
            this._ClassBreaksRenderer = (IClassBreaksRenderer)renderer;
            if (_ClassBreaksRenderer == null) return;
            IClassBreaksUIProperties clbUIPro = _ClassBreaksRenderer as IClassBreaksUIProperties;
            string method = "Manual";
            if (clbUIPro != null)
            {
                ESRI.ArcGIS.esriSystem.UID uid = clbUIPro.Method;
                if (uid == null)
                {
                    method = "Manual";
                    cmbClasses.Enabled = false;
                }
                else
                {
                    switch (uid.Value.ToString())
                    {
                        case "{62144BEA-E05E-11D1-AAAE-00C04FA334B3}":
                            method = "Natural Breaks (Jenks)";
                            break;
                        case "{62144BE1-E05E-11D1-AAAE-00C04FA334B3}":
                            method = "Equal Interval";
                            break;
                        case "{62144BE8-E05E-11D1-AAAE-00C04FA334B3}":
                            method = "Defined Interval";
                            cmbClasses.Enabled = false;
                            break;
                        case "{62144BE9-E05E-11D1-AAAE-00C04FA334B3}":
                            method = "Quantile";
                            break;
                        case "{DC6D8015-49C2-11D2-AAFF-00C04FA334B3}":
                            method = "Standard Deviation";
                            cmbClasses.Enabled = false;
                            break;
                        case "{C79EB120-E98E-4AF9-903D-70273E0C140E}":
                            method = "Geometrical Interval";
                            break;
                        default:
                            method = "Manual";
                            cmbClasses.Enabled = false;
                            break;
                    }
                }
            }
            cmbMethods.Text = method;
            cmbFields.Text = _ClassBreaksRenderer.Field;
            cmbClasses.Text = _ClassBreaksRenderer.BreakCount.ToString();
            ShowRenderer();
        }

        /// <summary>
        /// 显示渲染
        /// </summary>
        private void ShowRenderer()
        {
            BreakList.Clear();
            lowerBreak.Clear();
            SymbolList.Clear();
            imageList1.Images.Clear();
            if (_ClassBreaksRenderer == null) return;
            IClassBreaksUIProperties clbUIPro = _ClassBreaksRenderer as IClassBreaksUIProperties;            
            int breakCount = _ClassBreaksRenderer.BreakCount;
            for (int i = 0; i < breakCount; i++)
            {
                ISymbol symbol = _ClassBreaksRenderer.get_Symbol(i);
                this.imageList1.Images.Add(SymbolHelper.DrawSymbol(symbol, 16, 16), Color.White);
                SymbolList.Add(symbol);
                double lowBreak = clbUIPro.get_LowBreak(i);
                double classBreak = _ClassBreaksRenderer.get_Break(i);
                lowerBreak.Add(lowBreak);
                BreakList.Add(classBreak);
                string strLabel = _ClassBreaksRenderer.get_Label(i);
                ListViewItem listItem = new ListViewItem();
                listItem.SubItems.Add(lowBreak + " - " + classBreak);
                listItem.SubItems.Add(strLabel);
                labels.Add(strLabel);
                listItem.ImageIndex = i;
                listView.Items.Add(listItem);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkDesc_CheckedChanged(object sender, EventArgs e)
        {
            if (IsReady && listView.Items.Count > 0)
            {
                ReBoundImageList(!chkDesc.Checked);
            }
        }

        /// <summary>
        /// 重新绑定图片
        /// </summary>
        /// <param name="ascend"></param>
        private void ReBoundImageList(bool ascend)
        {
            if (listView.Items.Count == 0) return;
            this.imageList1.Images.Clear();
            SymbolList.Clear();
            IColorRamp myColorRamp = cmbColorRamp.SelectedColorRamp;
            for (int i = 0; i < listView.Items.Count; i++)
            {
                ISymbol pSymbol = null;
                int k = ascend ? i : listView.Items.Count-1 - i;
                switch (_FeatureLayer.FeatureClass.ShapeType)
                {
                    case esriGeometryType.esriGeometryMultipoint:
                    case esriGeometryType.esriGeometryPoint:
                        ISimpleMarkerSymbol ismsymbol = new SimpleMarkerSymbolClass();
                        ismsymbol.Color = myColorRamp.get_Color((k * myColorRamp.Size) / listView.Items.Count);
                        ismsymbol.Outline = true;
                        ismsymbol.OutlineSize = 1;
                        ismsymbol.OutlineColor = (IColor)Converter.ToRGBColor(Color.Black);
                        ismsymbol.Style = esriSimpleMarkerStyle.esriSMSCircle;
                        ismsymbol.Size = 4;
                        pSymbol = (ISymbol)ismsymbol;
                        break;
                    case esriGeometryType.esriGeometryPolyline:
                    case esriGeometryType.esriGeometryLine:
                        ISimpleLineSymbol islsymbol = new SimpleLineSymbolClass();
                        islsymbol.Color = myColorRamp.get_Color((k * myColorRamp.Size) / listView.Items.Count);
                        islsymbol.Width = 0.4;
                        pSymbol = (ISymbol)islsymbol;
                        break;
                    case esriGeometryType.esriGeometryPolygon:
                        ISimpleFillSymbol isfsymbol = new SimpleFillSymbolClass();
                        isfsymbol.Color = myColorRamp.get_Color((k * myColorRamp.Size) / listView.Items.Count);
                        isfsymbol.Style = esriSimpleFillStyle.esriSFSSolid;
                        isfsymbol.Outline.Width = 0.4;
                        pSymbol = (ISymbol)isfsymbol;
                        break;
                    default:
                        break;
                }
                SymbolList.Add(pSymbol);
                this.imageList1.Images.Add(SymbolHelper.DrawSymbol(pSymbol, 16, 16), Color.White);
            }
            this.listView.Refresh();
        }

        /// <summary>
        /// 字段选择改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cmbFields_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cmbFields.Text == "<空>"){
                cmbClasses.Enabled = false;
                listView.Items.Clear();
                BreakList.Clear();
                lowerBreak.Clear();
            }                
            else
            {
                progressBarX1.Visible = true;
                this.Cursor = Cursors.WaitCursor;
                Application.DoEvents();
                IsReady = false;
                cmbClasses.Enabled = true;
                int maxSampleSize = 20000;
                int classes = 5;
                double[] breaks = RendererHelper.NaturalBreak(_FeatureLayer, cmbFields.Text, ref classes, cmbMethods.Text, maxSampleSize);
                this.cmbClasses.Text = classes.ToString();
                ReClassifyBreaks(breaks);
                ReBoundImageList(!chkDesc.Checked);
                IsReady = true;
                progressBarX1.Visible = false;
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// 选择级数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cmbClasses_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listView.Items.Count == 0 || !IsReady || cmbFields.Text == "<空>" || string.IsNullOrWhiteSpace(cmbFields.Text)) return;
            int classes = 0;
            if (!int.TryParse(cmbClasses.Text, out classes)) return;
            progressBarX1.Visible = true;
            this.Cursor = Cursors.WaitCursor;
            Application.DoEvents();
            IsReady = false;
            int maxSampleSize = 20000;
            double[] breaks = RendererHelper.NaturalBreak(_FeatureLayer, cmbFields.Text, ref classes, cmbMethods.Text, maxSampleSize);
            ReClassifyBreaks(breaks);
            ReBoundImageList(!chkDesc.Checked);
            IsReady = true;
            progressBarX1.Visible = false;
            this.Cursor = Cursors.Default;
        }

        /// <summary>
        /// 方法选择改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbMethods_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listView.Items.Count == 0 || !IsReady || cmbFields.Text == "<空>" || string.IsNullOrWhiteSpace(cmbFields.Text)) return;            
            if (cmbMethods.Text == "Manual")
                cmbClasses.Enabled = false;
            else
            {
                int classes = 0;
                if (!int.TryParse(cmbClasses.Text, out classes)) return;
                progressBarX1.Visible = true;
                this.Cursor = Cursors.WaitCursor;
                Application.DoEvents();
                IsReady = false;
                int maxSampleSize = 20000;
                string defaultMethod = cmbMethods.Text;
                double[] breaks = RendererHelper.NaturalBreak(_FeatureLayer, cmbFields.Text, ref classes, defaultMethod, maxSampleSize);
                cmbClasses.Text = classes.ToString();
                if (defaultMethod == "Defined Interval" || defaultMethod == "Standard Deviation")
                    cmbClasses.Enabled = false;
                else
                    cmbClasses.Enabled = true;
                ReClassifyBreaks(breaks);
                ReBoundImageList(!chkDesc.Checked);
                IsReady = true;
                progressBarX1.Visible = false;
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="breakValues"></param>
        private void ReClassifyBreaks(double[] breakValues)
        {
            listView.Items.Clear();
            BreakList.Clear();
            lowerBreak.Clear();
            double low = Math.Round(breakValues[0], 6) - 0.000001;
            for (int i = 1; i < breakValues.Count(); i++)
            {
                BreakList.Add(Math.Round(breakValues[i], 6));
                lowerBreak.Add(low);
                low = breakValues[i] + 0.00001;
                ListViewItem listItem = new ListViewItem();
                string val = lowerBreak[i - 1] + " - " + BreakList[i - 1];
                listItem.SubItems.Add(val);
                listItem.SubItems.Add(val);
                labels.Add(val);
                listItem.ImageIndex = i - 1;
                listView.Items.Add(listItem);
            }
            BreakList[BreakList.Count - 1] += 0.000001;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbColorRamp_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listView.Items.Count == 0 || !IsReady || cmbFields.Text == "<空>" || string.IsNullOrWhiteSpace(cmbFields.Text)) return;
        }

        /// <summary>
        /// 编辑列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listView_MouseUp(object sender, MouseEventArgs e)
        {
            _ItemHitTestInfo = this.listView.HitTest(e.X, e.Y);
            if (_ItemHitTestInfo.SubItem == null) return;
            int index = _ItemHitTestInfo.Item.Index;
            int location = this.listView.Columns[0].Width + this.listView.Location.X;
            int column1X = location + this.listView.Columns[1].Width;
            int column2X = column1X + this.listView.Columns[2].Width;
            if (e.X < location)
            {
                this.Cursor = Cursors.WaitCursor;
                ISymbol pSymbol = (ISymbol)SymbolList[index];
                SymbolList[index] = pSymbol;
                this.imageList1.Images[index] = SymbolHelper.DrawSymbol(pSymbol, 16, 16);
                this.listView.Refresh();
                this.Cursor = Cursors.Default;
            }
            else if (e.X < column1X)
            {
                this.editBox.Size = new Size(this.listView.Columns[1].Width, _ItemHitTestInfo.Item.Bounds.Height);
                this.editBox.Location = new System.Drawing.Point(location, _ItemHitTestInfo.Item.Bounds.Y);
                this.editBox.Show();
                this.editBox.Text = string.Format("{0}", BreakList[index]);//pListViewHitTestInfo.Item.SubItems[2].Text;
                this.editBox.SelectAll();
                this.editBox.Focus();
                this.editBox.Tag = "break";
            }
            else if (e.X < column2X)
            {
                this.editBox.Size = new Size(this.listView.Columns[2].Width, _ItemHitTestInfo.Item.Bounds.Height);
                this.editBox.Location = new System.Drawing.Point(column1X, _ItemHitTestInfo.Item.Bounds.Y);
                this.editBox.Show();
                this.editBox.Text = labels[index];//pListViewHitTestInfo.Item.SubItems[2].Text;
                this.editBox.SelectAll();
                this.editBox.Focus();
                this.editBox.Tag = "label";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void editBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
            {
                this._IsCancel = false;
                this.editBox.Hide();
            }
            else if (e.KeyChar == '\x001b')
            {
                this._IsCancel = true;
                this.editBox.Hide();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void editBox_LostFocus(object sender, EventArgs e)
        {
            if (this._IsCancel)
            {
                this._IsCancel = false;
                this.editBox.Hide();
            }
            else
            {
                if (_ItemHitTestInfo.SubItem != null)
                {
                    int index = _ItemHitTestInfo.Item.Index;
                    double newBreak = 0;
                    if (editBox.Tag.ToString() == "label" && this.editBox.Text != labels[index])
                    {
                        this.listView.Items[index].SubItems[2].Text = this.editBox.Text;
                        labels[index] = this.editBox.Text;
                    }
                    else if (editBox.Tag.ToString() == "break" && double.TryParse(this.editBox.Text, out newBreak) && newBreak != BreakList[index])
                    {
                        BreakList[index] = newBreak;
                        this.listView.Items[index].SubItems[1].Text = lowerBreak[index] + " - " + newBreak;
                        if (index < listView.Items.Count-1)
                        {
                            lowerBreak[index + 1] = newBreak + 0.00001;
                            this.listView.Items[index + 1].SubItems[1].Text = lowerBreak[index + 1] + " - " + BreakList[index + 1];
                        }
                        this.cmbClasses.Enabled = false;
                        IsReady = false;
                        cmbMethods.Text = "Manual";
                        IsReady = true;
                    }
                }
                this._IsCancel = true;
                this.editBox.Hide();
            }
        }
                
    }
}
